#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <cassert>
#include <iostream>

class Channel
{
public:
    Channel(int wfd, int pid)
        :_wfd(wfd)
        , _process(pid)
    {}
    ~Channel()
    {}

    void SubProcessCloseBrother()
    {
        close(_wfd);
    }

    void Close()
    {
        std::cout << "关闭" << _process << "的信道" << std::endl;
        close(_wfd);
        std::cout << _process << "的信道关闭成功" << std::endl;
    }

    void Wait()
    {
        waitpid(_process, nullptr, 0);
        std::cout << "进程" << _process << "已被成功回收" << std::endl;
    }

    // 确保调用该函数的信道为当前最后启动的 或者 事先关闭所有子进程的写入端，否则会造成死锁
    void CloseAndWait()
    {
        close(_wfd);
        std::cout << _process << "的信道关闭成功" << std::endl;
        waitpid(_process, nullptr, 0);
        std::cout << "进程" << _process << "已被成功回收" << std::endl;
    }

    void ExecuteTask(int code)
    {
        std::cout << "将任务" << code << "派遣给" << _process << std::endl;
        write(_wfd, &code, sizeof(code));
    }

    int GetPid()
    {
        return _process;
    }
private:
    int _wfd;
    pid_t _process;
};

class ChannelManager
{
public:
    void Insert(Channel&& channel)
    {
        _Channels.push_back(channel);
    }

    int Size()
    {
        return _Channels.size();
    }

    void GiveTask(int code)
    {
        int channel = SelectChannel();
        std::cout << "选择进程: " << _Channels[channel].GetPid() << std::endl;
        _Channels[channel].ExecuteTask(code);
    }

    // 方案1：先关闭后回收
    void CloseChannels()
    {
        for(auto& channel : _Channels)
        {
            channel.Close();
        }
    }

    void WaitProcesses()
    {
        for(auto& channel : _Channels)
        {
            std::cout << "回收进程" << channel.GetPid() << std::endl;
            channel.Wait();
        }
    }

    // 方案2：反向关闭回收
    // void CloseAndWait()
    // {
    //     for(int i = _Channels.size() - 1; i >= 0; i--)
    //     {
    //         _Channels[i].CloseAndWait();
    //     }
    // }

    // 方案3：关闭所有子进程的写入端，可以任意方式关闭回收
    void CloseAndWait()
    {
        for(auto& channel : _Channels)
        {
            channel.CloseAndWait();
        }
    }

    void SubProcessCloseBrothers()
    {
        for(auto& channel : _Channels)
        {
            channel.SubProcessCloseBrother();
        }
    }
    
private:
    int SelectChannel()
    {
        // 轮询分派任务
        static int next = 0;
        assert(_Channels.size());
        int tmp = next;
        next = (next + 1) % _Channels.size();
        return tmp;
    }
    std::vector<Channel> _Channels;
};